package org.xu.logic;

import com.core.data.Reply;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.http.HttpMethodName;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.xu.config.CosClientManager;
import org.xu.entity.AttachmentModel;
import org.xu.service.AttachmentService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
@Service
public class FileLogicImpl implements FileLogic{

    // 是否包含 后缀名
    private static final Predicate<String> predicate = fileName -> fileName != null && fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") < fileName.length() - 1;
    private static final String FILE_VIEW_URL = "https://ares.uat.yixincapital.com/ares-web/api/file/showFile/";
    @Autowired
    private AttachmentService attachmentService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private CosClientManager cosClientManager;

    public void downLoad(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        List<AttachmentModel> modelList = attachmentService.listByApplyNos(Arrays.asList("263339","258127","264160","248550"));
        Map<String, List<AttachmentModel>> applyNoEntityMap = modelList.stream().collect(Collectors.groupingBy(AttachmentModel::getApplyNo));
        if (applyNoEntityMap.isEmpty()){
            return;
        }
        String fileName = "压缩包" + ".zip";
        try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            ZipOutputStream out = new ZipOutputStream(outputStream);
            Set<String> applyNoSet = applyNoEntityMap.keySet();
            for (String applyNo : applyNoSet) {
                List<AttachmentModel> models = applyNoEntityMap.get(applyNo);
                String directorName = applyNo + "\\";
                out.putNextEntry(new ZipEntry(directorName));
                Map<String,Integer> entryNameMap = new HashMap<>(); // 重命名 文件夹的文件名称
                for (AttachmentModel model : models) {
                    String completeFileName = getCompleteFileName(model.getFileName(), model.getOriginalFilename(), model.getUrl());
                    String url = FILE_VIEW_URL + completeFileName + "?url=" + model.getUrl();
                    try {
                        ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
                        byte[] body = response.getBody();
                        if (body != null){
                            out.putNextEntry(new ZipEntry(directorName + generateEntryName(entryNameMap,completeFileName,model.getUrl())));
                            out.write(body, 0, body.length);
                            out.closeEntry();
                        }
                    }catch (Exception e){
                        log.error("打包下载，数据获取失败,url:{},URL:{}",model.getUrl(),url,e);
                    }
                }
            }
            byte[] bytes = outputStream.toByteArray();
            out.close();
            String header = httpServletRequest.getHeader("User-Agent").toUpperCase();
            if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
                fileName = URLEncoder.encode(fileName, "utf-8");
                //IE下载文件名空格变+号问题
                fileName = fileName.replace("+", "%20");
            } else {
                fileName = new String(fileName.getBytes(), "ISO8859-1");
            }
            httpServletResponse.reset();
            httpServletResponse.setContentType("text/plain");
            httpServletResponse.setContentType("application/octet-stream; charset=utf-8");
            httpServletResponse.setHeader("Location", fileName);
            httpServletResponse.setHeader("Cache-Control", "max-age=0");
            httpServletResponse.setHeader("Content-Disposition", "attachment; filename=" + fileName);
            BufferedOutputStream outPutStream = new BufferedOutputStream(httpServletResponse.getOutputStream());
            outPutStream.write(bytes, 0, bytes.length);
            outPutStream.close();
        }catch (Exception e) {
            log.error("打包下载失败,",e);
        }
    }

    private String generateEntryName(Map<String,Integer> entryNameMap,String name,String url){
        Integer count = entryNameMap.get(name);
        if (count == null){
            entryNameMap.put(name,0);
            return name;
        }
        count ++;
        entryNameMap.put(name,count);
        String fileSuffix = "";
        if (url != null && url.lastIndexOf("/") != -1 && url.lastIndexOf(".") != -1 && url.lastIndexOf(".") < url.length() - 1) {
            fileSuffix = url.substring(url.lastIndexOf("."));
        }
        return name.substring(0,name.indexOf(".")) + "(" + count + ")" + fileSuffix;
    }

    /**
     * 获取文件后缀
     */
    private static String getCompleteFileName(String fileName,String originalFilename, String url) {
        String name = "附件";
        if (!StringUtils.isEmpty(fileName)){
            name = fileName;
        }else if (!StringUtils.isEmpty(originalFilename)){
            name = originalFilename;
        }
        if (predicate.test(name)){
            return name;
        }else {
            String fileSuffix = "";
            if (url != null && url.lastIndexOf("/") != -1 && url.lastIndexOf(".") != -1 && url.lastIndexOf(".") < url.length() - 1) {
                fileSuffix = url.substring(url.lastIndexOf("."));
            }
            return name + fileSuffix;
        }
    }

    @Override
    public void downLoadSimple(HttpServletRequest request, HttpServletResponse response) {
        try (FileOutputStream fos = new FileOutputStream("D:\\tmp\\test\\example.zip");
             ZipOutputStream zipOut = new ZipOutputStream(fos)) {
            // 创建一个文件夹条目
            ZipEntry folderEntry = new ZipEntry("example_folder/");
            zipOut.putNextEntry(folderEntry);
            zipOut.closeEntry();
            // 创建一个文件条目
            File sourceFile = new File("D:\\tmp\\example.txt");
            ZipEntry fileEntry = new ZipEntry("example_folder/example.txt");
            zipOut.putNextEntry(fileEntry);
            // 读取源文件内容并写入 ZIP 条目
            try (FileInputStream fis = new FileInputStream(sourceFile)) {
                byte[] bytes = new byte[1024];
                int length;
                while ((length = fis.read(bytes)) >= 0) {
                    zipOut.write(bytes, 0, length);
                }
            }
            // 关闭当前文件条目
            zipOut.closeEntry();
             sourceFile = new File("D:\\tmp\\SampleVideo_320x240_10mb.3gp");
             fileEntry = new ZipEntry("example_folder/SampleVideo_320x240_10mb.3gp");
            zipOut.putNextEntry(fileEntry);
            // 读取源文件内容并写入 ZIP 条目
            try (FileInputStream fis = new FileInputStream(sourceFile)) {
                byte[] bytes = new byte[1024];
                int length;
                while ((length = fis.read(bytes)) >= 0) {
                    zipOut.write(bytes, 0, length);
                }
            }
            // 关闭当前文件条目
            zipOut.closeEntry();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取腾讯云附加预览地址
     */
    @Override
    public Reply<String> showUrl(String url) {
        COSClient cosClient = cosClientManager.getCosClient();
        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        String bucketName = "test-cos80502-1308123821";
        // 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
        String key = "upload/" + url;
        // 设置签名过期时间(可选), 若未进行设置则默认使用 ClientConfig 中的签名过期时间(1小时)
        // 这里设置签名在半个小时后过期
        Date expirationDate = new Date(System.currentTimeMillis() + 30 * 60 * 1000);
// 填写本次请求的参数，需与实际请求相同，能够防止用户篡改此签名的 HTTP 请求的参数
        Map<String, String> params = new HashMap<String, String>();
        params.put("param1", "value1");
        // 填写本次请求的头部，需与实际请求相同，能够防止用户篡改此签名的 HTTP 请求的头部
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("header1", "value1");
        // 请求的 HTTP 方法，上传请求用 PUT，下载请求用 GET，删除请求用 DELETE
        HttpMethodName method = HttpMethodName.GET;
        URL url2 = cosClient.generatePresignedUrl(bucketName, key, expirationDate, method, headers, params);
        System.out.println(url2.toString());
        return Reply.success(url2.toString());
    }


}
